/*
 *  Class name: EntityRestClient.java
 *  Version: 1.0
 *  Date: 14.12.2013
 */
package cz.muni.fi.pa165.soccergamesarchive.restclient.rest;

import cz.muni.fi.pa165.soccergamesarchive.common.providers.XStreamXmlProvider;
import cz.muni.fi.pa165.soccergamesarchive.restclient.utils.LoginHandler;
import java.util.List;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.client.ClientConfig;

import static cz.muni.fi.pa165.soccergamesarchive.restclient.utils.LoginHandler.LoginCredentials;
import static javax.ws.rs.client.ClientBuilder.newClient;
import static javax.ws.rs.client.Entity.entity;
import static org.glassfish.jersey.client.authentication.HttpAuthenticationFeature.basic;

/**
 *
 * @author Michal Ďuriš
 * @param <T>
 */
public abstract class EntityRestClient<T> {

    private static final String BASE_URI = "http://sga-durismichal.rhcloud.com/sga/rest/";

    private static final String ADD_OPERATION_PATH = "new";
    private static final String CHANGE_OPERATION_PATH = "change";
    private static final String REMOVE_OPERATION_PATH = "delete";
    private static final String GET_LIMITED_OPERATION_PATH = "getlimnumber";
    private static final String GET_COUNT_OPERATION_PATH = "count";

    private static LoginCredentials loginCredentials = null;

    protected Client restClient;
    protected WebTarget restClientTargetResource;

    private final Class<T> entityClass;

    public EntityRestClient(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract String getEntityPath();

    protected abstract GenericType<List<T>> getGenericEntityTypeList();

    public boolean connect() {

        restClient = newClient(new ClientConfig().register(
                XStreamXmlProvider.class));

        if (!getLoginCredentials()) {
            return false;
        }

        restClient.register(basic(loginCredentials.getUsername(),
                loginCredentials.getPassword()));

        restClientTargetResource = restClient.target(BASE_URI);

        try {
            if (restClientTargetResource.request(
                    MediaType.TEXT_PLAIN).get().getStatus()
                != Response.Status.OK.getStatusCode()) {

                restClientTargetResource = restClientTargetResource.path(
                        getEntityPath());

                return true;
            }
        } catch (ProcessingException ex) {
            //@TODO: Logger or something
            System.err.println("Processing error in rest client " + ex);
        }

        return false;
    }

    private synchronized boolean getLoginCredentials() {

        if (loginCredentials == null) {

            loginCredentials = LoginHandler.getLoginCredentials();

            if (loginCredentials == null) {
                return false;
            }
        }

        return true;
    }

    public void disconnect() {
        if (restClient != null) {
            restClient.close();
        }
    }

    public T addEntity(T entity) throws RuntimeException {

        return restClientTargetResource.path(ADD_OPERATION_PATH).request(
                MediaType.TEXT_XML).post(entity(entity,
                                MediaType.TEXT_XML), entityClass);
    }

    public T changeEntity(T entity) throws RuntimeException {

        return restClientTargetResource.path(CHANGE_OPERATION_PATH).request(
                MediaType.TEXT_XML).post(entity(entity,
                                MediaType.TEXT_XML), entityClass);
    }

    public void removeEntity(T entity) throws RuntimeException {

        restClientTargetResource.path(REMOVE_OPERATION_PATH).request(
                MediaType.TEXT_XML).post(entity(entity,
                                MediaType.TEXT_XML), entityClass);
    }

    public List<T> getEntityList(int offset, int limit) throws RuntimeException {

        return restClientTargetResource.path(
                GET_LIMITED_OPERATION_PATH + "/" + offset + "/" + limit)
                .request(
                        MediaType.TEXT_XML).get(getGenericEntityTypeList());
    }

    public int getAllEntitiesCount() throws RuntimeException {

        return restClientTargetResource.path(GET_COUNT_OPERATION_PATH).request(
                MediaType.TEXT_PLAIN).get(Integer.class);
    }

}
